Vector Databases

LanceDB برای RAG چندوجهی: ذخیره و پرس‌وجوی جفت‌های تصویر-متن

سیستم‌های تولید تقویت‌شده با بازیابی (RAG) تا اخیراً عمدتاً متنی بوده‌اند. با این حال، برنامه‌های هوش مصنوعی مدرن به طور فزاینده‌ای به قابلیت بازیابی و استدلال همزمان روی داده‌های بصری و متنی نیاز دارند. اینجاست که RAG چندوجهی وارد عمل می‌شود. در حالی که پایگاه‌های داده برداری سنتی با پیچیدگی مدیریت انواع داده‌های متعدد و بارهای باینری بزرگ دست‌وپنجه نرم می‌کنند، LanceDB یک راه‌حل ذخیره‌سازی ستونی قوی را ارائه می‌دهد که به طور خاص برای بارهای کاری هوش مصنوعی طراحی شده است.

در این راهنما، ما بررسی خواهیم کرد که چگونه از LanceDB برای ذخیره و پرس‌وجوی کارآمد جفت‌های تصویر-متن استفاده کنیم. ما نشان خواهیم داد که چگونه با تولید جاسازی (embedding)، ورود داده و منطق بازیابی مورد نیاز برای یک سیستم چندوجهی، برخورد کنیم.

چرا LanceDB برای داده‌های چندوجهی؟

LanceDB یک پایگاه داده برداری متن‌باز و دوستانه برای توسعه‌دهندگان است که از فرمت Lance استفاده می‌کند. برخلاف پایگاه‌های داده مبتنی بر ردیف، Lance برای دسترسی تصادفی و فایل‌های باینری بزرگ بهینه شده است، که آن را ایده‌آل برای ذخیره تصاویر در کنار جاسازی‌های برداری آن‌ها می‌کند. مزایای کلیدی شامل موارد زیر است:

  • ذخیره‌سازی بدون عملیات (Zero-Op): این پایگاه داده به صورت جاسازی‌شده (embedded) درون برنامه شما اجرا می‌شود و پیچیدگی زیرساخت را کاهش می‌دهد.
  • فیلترگذاری کارآمد: این پایگاه داده از فیلترگذاری متادیتا در کنار شباهت برداری پشتیبانی می‌کند، که برای محدود کردن نتایج جستجو بر اساس دسته، تاریخ یا منبع حیاتی است.
  • پشتیبانی از اشیاء بزرگ: این پایگاه داده به طور بومی با داده‌های باینری بزرگ (مانند تصاویر) برخورد می‌کند و در بسیاری از سناریوها به وابستگی به ذخیره‌سازی blob خارجی نیاز ندارد.

راه‌اندازی و نصب

برای شروع، شما باید LanceDB و یک مدل جاسازی چندوجهی را نصب کنید. در این مثال، ما از transformers با یک مدل CLIP برای تولید جاسازی‌ها استفاده خواهیم کرد.


# نصب وابستگی‌ها
pip install lancedb transformers torch pillow

گام 1: تولید جاسازی‌های چندوجهی

پایه‌ی RAG چندوجهی، هم‌راستایی تصاویر و متن در یک فضای برداری مشترک است. ما از یک مدل CLIP برای تولید جاسازی‌ها برای هر دو تصویر و پرس‌وجوهای متنی استفاده می‌کنیم. هنگام جستجو، شما می‌توانید با متن پرس‌وجو کنید تا تصاویر مرتبط را پیدا کنید، یا برعکس.


import torch
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
import base64
import numpy as np

# بارگذاری مدل CLIP
model_name = "openai/clip-vit-base-patch32"
processor = CLIPProcessor.from_pretrained(model_name)
model = CLIPModel.from_pretrained(model_name)

def get_image_embedding(image_path):
    """تولید جاسازی برای یک تصویر."""
    image = Image.open(image_path)
    inputs = processor(images=image, return_tensors="pt")
    with torch.no_grad():
        outputs = model.get_image_features(**inputs)
    return outputs.cpu().numpy().flatten()

def get_text_embedding(text):
    """تولید جاسازی برای یک پرس‌وجوی متنی."""
    inputs = processor(text=text, return_tensors="pt", padding=True)
    with torch.no_grad():
        outputs = model.get_text_features(**inputs)
    return outputs.cpu().numpy().flatten()

گام 2: ورود جفت‌های تصویر-متن

ما یک جدول LanceDB ایجاد خواهیم کرد که داده‌های تصویر (که در این مثال برای پرتابل بودن به صورت Base64 کدگذاری شده‌اند، هرچند بایت‌های خام برای عملکرد ترجیح داده می‌شوند)، زیرنویس (caption) و جاسازی برداری را ذخیره می‌کند.


import lancedb
import uuid

# راه‌اندازی پایگاه داده
db = lancedb.connect("./multimodal_db")

# ایجاد جدول اگر وجود ندارد
# نکته: در تولید، ممکن است بایت‌های تصویر را مستقیماً ذخیره کنید یا از URI استفاده کنید
table = db.open_table("images") if db.table_names() else db.create_table("images", mode="create")

# داده نمونه
sample_data = [
    {
        "id": str(uuid.uuid4()),
        "caption": "یک گلدن رتریور در حال بازی در پارک",
        "image_data": open("dog.jpg", "rb").read(), # خواندن بایت‌های تصویر
        "vector": get_image_embedding("dog.jpg"),
    },
    {
        "id": str(uuid.uuid4()),
        "caption": "یک کتابخانه دنج با قفسه‌های کتاب",
        "image_data": open("library.jpg", "rb").read(),
        "vector": get_image_embedding("library.jpg"),
    }
]

# افزودن داده به جدول
table.add(sample_data)

گام 3: انجام جستجوی چندوجهی

قدرت RAG چندوجهی در بازیابی بین‌مدالی (cross-modal) نهفته است. یک کاربر ممکن است "عکس‌های سگ‌ها را برایم پیدا کن" را تایپ کند و سیستم باید بر اساس پرس‌وجوی متنی، تصاویر بصری‌تر مشابه را برگرداند.


def search_images(text_query, top_k=5):
    """جستجو برای تصاویر بر اساس یک پرس‌وجوی متنی."""
    # تولید جاسازی برای پرس‌وجوی متنی
    query_vector = get_text_embedding(text_query)
    
    # انجام جستجوی برداری با فیلتر متادیتا
    # اینجا ما صرفاً با شباهت برداری جستجو می‌کنیم
    results = table.search(query_vector).limit(top_k).to_pandas()
    
    # کدگذاری مجدد داده تصویر برای نمایش (اختیاری)
    for idx, row in results.iterrows():
        print(f"نتیجه {idx}: {row['caption']}")
        # در یک برنامه واقعی، شما row['image_data'] را کدگذاری مجدد کرده و نمایش می‌دهید
        # img = Image.open(io.BytesIO(row['image_data']))
        
    return results

# اجرای جستجو
results = search_images("سگ بامزه در حال بازی در فضای باز")
print(results[['id', 'caption', '_distance']])

نتیجه‌گیری

LanceDB یک مسیر ساده‌سازی‌شده برای ساخت برنامه‌های RAG چندوجهی ارائه می‌دهد با ساده‌سازی ذخیره‌سازی و بازیابی انواع داده‌های پیچیده. با هم‌راستایی جاسازی‌های متن و تصویر در یک فضای برداری مشترک، توسعه‌دهندگان می‌توانند تجربیات جستجوی شهودی ایجاد کنند که رابطه بین ظاهر یک شیء و توصیف آن را درک می‌کنند. با گسترش مدل‌های چندوجهی، ابزارهایی مانند LanceDB برای مدیریت زیرساخت داده‌ای زیربنایی ضروری خواهند بود.

Share: